package gsar.client;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


/*
Copyright (c) 2009, Eric Eaton, University of Maryland Baltimore County
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the University of Maryland Baltimore County nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/** Contains all the perceptions of the agent for the current timestep.
 * @author Eric Eaton
 */
public class Perceptions {
	
	/** The last action */
	private GWActionStatus m_lastAction = null;
	
	/** The agent structure for itself */
	private GWAgent m_selfSensors = null;
	
	/** An agent or object struct, or null if the short-range sensors weren't activated */
	private GWObject m_shortRangeSensors = null;
	
	/** A list of cells */
	private HashMap<GWCoordinate,GWCell> m_longRangeSensors = new HashMap<GWCoordinate, GWCell>();
	
	/** Constructor
	 * @param lastAction the last action the agent performed
	 * @param selfSensors the self-sensor data
	 * @param shortRangeSensors the short-range sensor data
	 * @param longRangeSensors the cells perceived by the long-range sensor
	 */
	public Perceptions(GWActionStatus lastAction, GWAgent selfSensors, 
			           GWObject shortRangeSensors, Collection<GWCell> longRangeSensors) {
		if (selfSensors == null)
			throw new IllegalArgumentException("selfSensors cannot be null");
		if (longRangeSensors == null)
			throw new IllegalArgumentException("longRangeSensors cannot be null");

		m_lastAction = lastAction;
		m_selfSensors = selfSensors;
		m_shortRangeSensors = shortRangeSensors;
		
		// initialize the long-range sensors
		for (GWCell cell : longRangeSensors) {
			m_longRangeSensors.put(cell.getCoordinates(), cell);
		}
	}


	public GWActionStatus getLastAction() { return m_lastAction; }

	public GWAgent getSelfSensors() { return m_selfSensors; }
 
	public GWObject getShortRangeSensors() { return m_shortRangeSensors; }

	public Collection<GWCell> getLongRangeSensors() { return m_longRangeSensors.values(); }
	
	
	private List<GWObject> m_perceivedObjects = null;
	
	/** Gets a list of the objects in the perception.
	 * @return list of all objects contained in the perception.
	 */
	public List<GWObject> listPerceivedObjects() {
		
		if (m_perceivedObjects != null)
			return m_perceivedObjects;
		
		// collect all objects in the long-range sensors
		m_perceivedObjects = new ArrayList<GWObject>();
		for (GWCell cell : getLongRangeSensors()) {
			GWObject occupant = cell.getOccupant();
			if (occupant != null)
				m_perceivedObjects.add(occupant);
		}
		
		// replace the long-range perceived obj with the short-range one
		if (m_shortRangeSensors != null) {
			for (GWObject obj : m_perceivedObjects) {
				if (obj.getCoordinates().equals(m_shortRangeSensors.getCoordinates()))
					m_perceivedObjects.remove(obj);
			}
			m_perceivedObjects.add(m_shortRangeSensors);
		}
		
		return m_perceivedObjects;
	}

	
	private Map<GWCoordinate, GWObject> m_locationToObject = null;

	
	/** Gets a hashmap from a location to the perceived object at that location.
	 *  @return a map from a coordinate location to the perceived object at that location.
	 */
	public Map<GWCoordinate, GWObject> locatePerceivedObjects() {
		
		if (m_locationToObject != null)
			return m_locationToObject;
		
		// hash each perceived object by its location
		List<GWObject> objs = listPerceivedObjects();
		m_locationToObject = new HashMap<GWCoordinate, GWObject>();
		for (GWObject obj : objs) {
			m_locationToObject.put(obj.getCoordinates(),obj);
		}
		
		return m_locationToObject;
	}
	

	/** Gets a list of the coordinates in the perception.
	 * @return the list of all coordinates contained in the perception.
	 */
	public Set<GWCoordinate> listPerceivedCoordinates() {
		return m_longRangeSensors.keySet();
	}
	
	
	/** Gets the perceived cell at the specified location
	 * @param coord the coordinate
	 * @return the perceived cell at that coordinate
	 */
	public GWCell getPerceivedCell(GWCoordinate coord) {
		return m_longRangeSensors.get(coord);
	}
	
	
	/** Gets the agent's current location
	 * @return the agent's current location
	 */
	public GWCoordinate getCurrentLocation() {
		return m_selfSensors.getCoordinates();
	}
	
	
	public String toString() {
		String str = "LastAction="+m_lastAction+"\n";
		str += "SelfSensors="+m_selfSensors+"\n";
		str += "ShortRange="+m_shortRangeSensors+"\n";
		str += "LongRange="+getLongRangeSensors();
		return str;
	}
	
}
